package com.contact.util;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

@SuppressWarnings("unchecked")
public final class ObjectUtils extends org.springframework.util.ObjectUtils {

    private static final Log logger = LogFactory.getLog(ObjectUtils.class);
    private static final String NESTED_DELIM = ".";

    private ObjectUtils() {
        //singleton
    }

    /**
     * Null safe equals operator. Works on arrays as well.
     * 
     * Replaced ObjectEquality.equals
     * 
     * @param obj1
     *            object compared to object 2
     * @param obj2
     *            object compared to object 1
     * @return true if objects are equal
     */
    public static boolean equals(Object obj1, Object obj2) {
        return nullSafeEquals(obj1, obj2);
    }

    public static <T extends Object> Class<T> getBeanClass(String className) {
        try {
            return (Class<T>) Class.forName(className);
        } catch (ClassNotFoundException e) {
            logger.error("Cannot find class for " + className, e);
        }

        return null;

    }

    /**
     * 
     * This calls a constructor of a class with no parameters even if it private.
     * 
     * @param cls
     *            - class to call constructor on
     * @return class
     */

    public static <T extends Object> T getBeanInstance(Class<T> cls) {
        T n = null;
        try {

            for (Constructor<?> c : cls.getDeclaredConstructors()) {
                c.setAccessible(true);

                if (c.getParameterTypes().length == 0) {
                    n = (T) c.newInstance((Object[]) null);
                    break;
                }
            }

        } catch (Exception e) { //NOPMD
            logger.error("Cannot create instance of " + cls.getCanonicalName(), e);
        }

        return n;

    }

    public static Class<?> getPropertyClass(Object bean, String attribute) {
        Class<?> returnClass = null;
        try {
            returnClass = PropertyUtils.getPropertyDescriptor(bean, attribute).getPropertyType();
        } catch (Exception e) {
            logger.error(String.format("Could not get Class for property %s on bean %s", attribute, bean), e);
        }
        return returnClass;
    }

    public static Object getEnumValue(Class<?> clazz, Object value) {
        Object enumValue = null;
        for (Object e : clazz.getEnumConstants()) {
            if (((Enum<?>) e).name().equals(value)) {
                enumValue = e;
            }

            if (enumValue != null) {
                break;
            }
        }
        return enumValue;
    }

    public static boolean hasValues(Object[] array) {
        return !isEmpty(array);
    }

    public static String getFieldValue(Object bean, String fieldKey) {
        String value = null;

        try {
            if (fieldKey.contains(NESTED_DELIM)) {
                value = BeanUtils.getNestedProperty(bean, fieldKey);
            } else {
                value = BeanUtils.getProperty(bean, fieldKey);
            }
        } catch (Exception e) { //NOPMD
            logger.error(String.format("Could not get field value for %s on bean %s", fieldKey, bean), e);
        }

        return value;
    }

    public static void setFieldValue(Object bean, String fieldKey, Object value) {
        try {
            BeanUtils.setProperty(bean, fieldKey, value);
        } catch (IllegalAccessException e) {
            logger.error(String.format("Could not set field value for %s on bean %s", fieldKey, bean), e);
        } catch (InvocationTargetException e) {
            logger.error(String.format("Could not set field value for %s on bean %s", fieldKey, bean), e);
        }

    }

}
